package data;

import java.io.File;
import java.io.IOException;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Vector;


import ch.ubique.inieditor.IniEditor;

public class Saver {

	String inputname;
	File out;
	IniEditor editor;

	private static final String root = "root";

	public Saver(String inputname){
		this.editor = new IniEditor();
		this.inputname = inputname;
		this.out = new File(inputname+".ini");
		loadFile();
	}

	public void loadFile(){
		System.out.println("Loading file - " + out.getAbsolutePath());
		try {
			if (!out.exists()){
				out.createNewFile();
				editor.addSection(root);
				editor.set(root, "inputname", inputname+ ".csv");
				editor.set(root, "nummirroring", "0");
				editor.set(root, "numclustering", "0");
				editor.set(root, "numconfiguration", "0");
				editor.set(root, "numcompression", "0");
			}
			editor.load(out);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void save(){
		editor.set(root, "lastModified", GregorianCalendar.getInstance().getTime().toString());
		try {
			editor.save(out);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void save(MirroringInput in, MirroringGDWithoutBS out){
		try{
			int numMirroring = Integer.parseInt(editor.get("root", "nummirroring"));
			numMirroring++;
			editor.set(root, "nummirroring", numMirroring+"");
			String mirroringSection = "Mirroring"+numMirroring; 
			editor.addSection(mirroringSection);
			editor.set(mirroringSection, "in_buffersize", in.get_bufferSize() + "");
			editor.set(mirroringSection, "in_disktype", in.get_diskType().toString());
			Vector<MirroringGDWithBS> vec = out.get_allResults();
			editor.set(mirroringSection, "numOfPoints", vec.size() + "");
			for (int i = 0; i < vec.size(); i++) {
				MirroringGDWithBS point = vec.get(i);
				editor.set(mirroringSection, "point"+i+"energy", point.get_energy()+"");
				editor.set(mirroringSection, "point"+i+"bufferSize", point.get_bufferSize() + "");
				editor.set(mirroringSection, "point"+i+"price", point.get_price() + "");
				editor.set(mirroringSection, "point"+i+"totaltu", point.get_timeUnitsTotalnumber() + "");
				editor.set(mirroringSection, "point"+i+"timeUnits", point.get_timeUnitsID().toString());
			}
		} catch (NumberFormatException e) {
			e.printStackTrace();
		}
		save();
	}

	public MirroringGDWithoutBS loadMirroring(int num){
		try{
			String mirroringSection = "Mirroring"+num; 
			//			if we want to get the input			
			//			editor.get(mirroringSection, "in_buffersize", in.get_bufferSize() + "");
			//			editor.get(mirroringSection, "in_disktype", in.get_diskType().toString());
			int numPoints = Integer.parseInt(editor.get(mirroringSection, "numOfPoints"));

			Vector<MirroringGDWithBS> vec = new Vector<MirroringGDWithBS>();
			for (int i = 0; i < numPoints; i++) {
				double energy = Double.parseDouble(editor.get(mirroringSection, "point"+i+"energy")); 
				double size = Double.parseDouble(editor.get(mirroringSection, "point"+i+"bufferSize"));
				double price = Double.parseDouble(editor.get(mirroringSection, "point"+i+"price"));
				int totalTimeUnits = Integer.parseInt(editor.get(mirroringSection, "point"+i+"totaltu"));

				String timeUnits = editor.get(mirroringSection, "point"+i+"timeUnits");
				timeUnits = timeUnits.replaceAll("[\\s\\[\\]]", "");
				String[] tus = timeUnits.split(",");
				Vector<Integer> timeUnitsVec = new Vector<Integer>();
				if (!timeUnits.isEmpty()){
					for (int j = 0; j < tus.length; j++) {
						timeUnitsVec.add(Integer.parseInt(tus[j]));
					}
				}
				MirroringGDWithBS mgdwbs = new MirroringGDWithBS(size, price, timeUnitsVec, energy, totalTimeUnits);
				vec.add(mgdwbs);
			}
			return new MirroringGDWithoutBS(vec);
		} catch (NumberFormatException e) {
			e.printStackTrace();
			return null;
		}
	}

	public void save(ClusteringInput in, ClusteringGraphData out){
		try{
			int numClustering = Integer.parseInt(editor.get(root, "numclustering"));
			numClustering++;
			editor.set(root, "numclustering", numClustering +"");
			String clusteringSection = "Configuration"+numClustering; 
			editor.addSection(clusteringSection);
			editor.set(clusteringSection, "in_dateStart", in.get_dateStart().getTime().toString());
			editor.set(clusteringSection, "in_dateEnd", in.get_dateEnd().getTime().toString());
			editor.set(clusteringSection, "in_numclusters", in.get_numClusters()+"");
			editor.set(clusteringSection, "in_priority", in.get_priorityParameter().toString());


			List<List<String> > vec = out.getClusters();

			editor.set(clusteringSection, "numOfPoints", vec.size() + "");
			for (int i = 0; i < vec.size(); i++) {
				List<String> point = vec.get(i);
				editor.set(clusteringSection, "point"+i, point + "");
			}
		} catch (NumberFormatException e) {
			e.printStackTrace();
		}
		save();
	}

	private ClusteringGraphData loadClustering(int num) {
		try{
			String clusteringSection = "Clustering"+num; 
			int numPoints = Integer.parseInt(editor.get(clusteringSection, "numOfPoints"));

			List<List<String> > vec = new Vector<List<String> >();
			for (int i = 0; i < numPoints; i++) {
				String timeUnits = editor.get(clusteringSection, "point"+i);
				timeUnits = timeUnits.replaceAll("[\\s\\[\\]]", "");
				String[] tus = timeUnits.split(",");
				List<String> lst = new Vector<String>();
				if (!timeUnits.isEmpty()){
					for (int j = 0; j < tus.length; j++) {
						lst.add(tus[j]);
					}
				}
				vec.add(lst);
			}
			return new ClusteringGraphData(vec);
		} catch (NumberFormatException e) {
			e.printStackTrace();
			return null;
		}
	}

	public void save(ConfigurationInput in, ConfigurationGraphData out){
		try{
			int numConfiguration = Integer.parseInt(editor.get(root, "numConfiguration"));
			numConfiguration++;
			editor.set(root, "numConfiguration", numConfiguration +"");
			String configurationSection = "Configuration"+numConfiguration; 
			editor.addSection(configurationSection);
			editor.set(configurationSection, "in_dateStart", in.get_dateStart().getTime().toString());
			editor.set(configurationSection, "in_dateEnd", in.get_dateEnd().getTime().toString());
			editor.set(configurationSection, "in_ordering", in.get_orderingParameter().toString());
			editor.set(configurationSection, "in_performence", in.get_performanceLimit() + "");
			editor.set(configurationSection, "in_power", in.get_powerConsumptionLimit() + "");
			editor.set(configurationSection, "in_price", in.get_priceLimit() + "");


			Vector<ConfigurationGraphObject> vec = out.get_ppp();

			editor.set(configurationSection, "numOfPoints", vec.size() + "");
			for (int i = 0; i < vec.size(); i++) {
				ConfigurationGraphObject point = vec.get(i);
				editor.set(configurationSection, "point"+i+"SATA", point.get_amountSATA()+"");
				editor.set(configurationSection, "point"+i+"SCSI", point.get_amountSCSI() + "");
				editor.set(configurationSection, "point"+i+"SSD", point.get_amountSSD() + "");
				editor.set(configurationSection, "point"+i+"performence", point.get_performance() + "");
				editor.set(configurationSection, "point"+i+"power", point.get_powerConsumption() + "");
				editor.set(configurationSection, "point"+i+"price", point.get_price() + "");
			}
		} catch (NumberFormatException e) {
			e.printStackTrace();
		}
		save();
	}

	public ConfigurationGraphData loadConfiguration(int num){
		try{
			String configurationSection = "Configuration"+num; 
			//			for getting the input
			//			editor.set(configurationSection, "in_dateStart", in.get_dateStart().toString());
			//			editor.set(configurationSection, "in_dateEnd", in.get_dateEnd().toString());
			//			editor.set(configurationSection, "in_ordering", in.get_orderingParameter().toString());
			//			editor.set(configurationSection, "in_performence", in.get_performanceLimit() + "");
			//			editor.set(configurationSection, "in_power", in.get_powerConsumption() + "");
			//			editor.set(configurationSection, "in_price", in.get_priceLimit() + "");

			int numPoints = Integer.parseInt(editor.get(configurationSection, "numOfPoints"));
			Vector<ConfigurationGraphObject> vec = new Vector<ConfigurationGraphObject>();

			editor.set(configurationSection, "numOfPoints", vec.size() + "");
			for (int i = 0; i < numPoints; i++) {
				int numSata = Integer.parseInt(editor.get(configurationSection, "point"+i+"SATA"));
				int numScsi = Integer.parseInt(editor.get(configurationSection, "point"+i+"SCSI"));
				int numSsd = Integer.parseInt(editor.get(configurationSection, "point"+i+"SSD"));
				double performence = Double.parseDouble(editor.get(configurationSection, "point"+i+"performence"));
				double power = Double.parseDouble(editor.get(configurationSection, "point"+i+"power"));
				double price = Double.parseDouble(editor.get(configurationSection, "point"+i+"price"));
				ConfigurationGraphObject tmp = new ConfigurationGraphObject(performence, power, price, numSsd, numScsi, numSata);
				vec.add(tmp);
			}
			return new ConfigurationGraphData(vec);
		} catch (NumberFormatException e) {
			e.printStackTrace();
			return null;
		}
	}

	public void save(CompressionGraphData out){
		try{
			int numCompression = Integer.parseInt(editor.get(root, "numCompression"));
			numCompression++;
			editor.set(root, "numCompression", numCompression +"");
			String compressionSection = "Compression" + numCompression; 
			editor.addSection(compressionSection);

			Vector<CompressionGraphObject> vec = out.get_amountResults();

			editor.set(compressionSection, "numOfPoints", vec.size() + "");
			for (int i = 0; i < vec.size(); i++) {
				CompressionGraphObject point = vec.get(i);
				editor.set(compressionSection, "point"+i+"emptyDisks",point.get_emptyDiskAmount()+"");
				editor.set(compressionSection, "point"+i+"performence",point.get_performance()+"");
			}
		} catch (NumberFormatException e) {
			e.printStackTrace();
		}
		save();
	}

	public CompressionGraphData loadCompression(int num){
		try{
			String compressionSection = "Compression" + num; 

			int numPoints = Integer.parseInt(editor.get(compressionSection, "numOfPoints"));

			Vector<CompressionGraphObject> vec = new Vector<CompressionGraphObject>();

			for (int i = 0; i < numPoints; i++) {

				int amount = Integer.parseInt(editor.get(compressionSection, "point"+i+"emptyDisks"));
				double performence = Double.parseDouble(editor.get(compressionSection, "point"+i+"performence"));
				CompressionGraphObject point = new CompressionGraphObject(amount, performence);
				vec.add(point);
			}
			return new CompressionGraphData(vec);
		} catch (NumberFormatException e) {
			e.printStackTrace();
			return null;
		}
	}

	public Vector<String> getFileContent() {
		String space = "|";
		Vector<String> ans = new Vector<String>();
		int numMirroring = Integer.parseInt(editor.get(root, "nummirroring"));
		int numClustering = Integer.parseInt(editor.get(root, "numclustering"));
		int numConfigurations = Integer.parseInt(editor.get(root, "numconfiguration"));
		int numCompression = Integer.parseInt(editor.get(root, "numcompression"));
		for (int i=1; i<=numMirroring; i++){
			String section = "Mirroring" + i;
			String res = section;
			res = res + space + editor.get(section, "in_buffersize");
			res = res + space + editor.get(section, "in_disktype");
			ans.add(res);
		}
		for (int i=1; i<=numClustering; i++){
			//			String section = "Clustering" + i;
			//TODO load clustering things
		}
		for (int i=1; i<=numConfigurations; i++){
			String section = "Configuration" + i;
			String res = section;
			res = res + space + editor.get(section, "in_dateStart");
			res = res + space + editor.get(section, "in_dateEnd");
			res = res + space + editor.get(section, "in_ordering");
			res = res + space + editor.get(section, "in_performence");
			res = res + space + editor.get(section, "in_power");
			res = res + space + editor.get(section, "in_price");
			ans.add(res);
		}
		for (int i=1; i<=numCompression; i++){
			String section = "Compression" + i;
			ans.add(section);
		}
		return ans;
	}

	public GraphData loadResults(String section) {
		try{
			if (section.startsWith("Configuration")){
				int number = Integer.parseInt(section.substring("Configuration".length()));
				return loadConfiguration(number);
			} else if (section.startsWith("Compression")){
				int number = Integer.parseInt(section.substring("Compression".length()));
				return loadCompression(number);
			} else if (section.startsWith("Clustering")){
				int number = Integer.parseInt(section.substring("Clustering".length()));
				return loadClustering(number);
			} else if (section.startsWith("Mirroring")){
				int number = Integer.parseInt(section.substring("Mirroring".length()));
				return loadMirroring(number);

			}
		}catch (NumberFormatException e) {
			e.printStackTrace();
		}
		return null;
	}

	public void save(AlgorithmInput input, GraphData data) {
		//TODO - make it less magil
		if (data instanceof CompressionGraphData){
			save((CompressionGraphData)data);
			System.out.println("Done saving compression");
			return;
		}
		if (data instanceof ClusteringGraphData){
			save((ClusteringInput)input, (ClusteringGraphData)data);
			System.out.println("Done saving clustering");
			return;
		}
		if (data instanceof MirroringGDWithoutBS){
			save((MirroringInput)input, (MirroringGDWithoutBS)data);
			System.out.println("Done saving mirroring");
			return;
		}
		if (data instanceof ConfigurationGraphData){
			save((ConfigurationInput)input, (ConfigurationGraphData)data);
			System.out.println("Done saving configuration");
			return;
		}
		System.out.println("Invalid blablabla");
	}



	//	public static void main(String[] args) {
	//		Vector v = new Vector<Integer>();
	//		v.add(1);
	//		v.add(1);
	//		v.add(1);
	//		v.add(2);
	//		v.add(1);
	//		v.add(1);
	//		v.add(3);
	//		System.out.println(v.toString());
	//		String[] tmp = v.toString().replaceAll("[\\s\\[\\]]", "").split("[\\[\\]],");
	//		System.out.println(Arrays.toString(tmp));
	//	}
}
